$(document).ready(function(){

    var fsSupport = true;

    init();

    function init() {

        if (!Detector.webgl) {
            alert('not support roam');
            document.getElementById('note').innerHTML = 'not support roam';
            document.getElementById('note').style.display = '';
            document.getElementById('cover_img').style.display = 'none';
            document.getElementById('spinner').style.display = 'none';
            return;
        }

        if(!bowser.mobile) {
            return;
        }

        if(!bowser.iphone) {
            return;
        }

        var noSleep = new NoSleep();
        noSleep.enable();

        var rotation = function () {
            var rotation = function (){
                $("#spinner").rotate({
                    angle: 0,
                    animateTo: 360,
                    callback: rotation,
                    duration: 1000
                });
            }
            rotation();
        };
        rotation();

        start();

    }

    function start() {

        var projectId = $('#project_id_input').val();
        var confUrl = '/browser/getConf/projectId/' + projectId;
        var confLoaded = false;
        var serverUrl = $('#server_url_input').val();

        var camera, scene, renderer;
        var effect, controls;
        var canvas = document.getElementById('canvas');

        var canvasWidth = $(window).width();
        var canvasHeight = $(window).height();
        var elementAspect = canvasWidth / canvasHeight;

        var isVR = false;
        var isVRReq = false;

        var cameraFov = 60;
        var cameraNearDis = 0.0001;
        var cameraFarDis = 1000;
        var cameraPx = 0;
        var cameraPy = 0;
        var cameraPz = 0;
        var cameraDis = 0;
        var cameraPhi = 0;
        var cameraTheta = 0;

        var textureLoadManager = new THREE.LoadingManager();
        var textureLoader = new THREE.TextureLoader(textureLoadManager);

        var targetStar = null;
        var targetStarTid = 0;
        var targetStarTime = 10;
        var targetStarCnt = 0;
        var targetStarTrigCnt = 0;

        var nodeOriginId = 0;
        var nodeArr = null;
        var nodeNum = 0;
        var nodeNewLoadDataArr = [];
        var nodeOldLoadDataArr = [];
        var nodeNewLoadIdArr = [];
        var nodeOldLoadIdArr = [];
        var curNodeObj = null;
        var curNodeSphereMesh = null;
        var curNodeArrowCtnObj = null;
        var nextNodeSphereMesh = null;
        var arrowCtnObjDis = 2;

        var nodeArrowNormalUrl = serverUrl + 'asset/img/arrow_normal.png';
        var nodeArrowSelectUrl = serverUrl + 'asset/img/arrow_select.png';
        var nodeArrowNormalTexture = null;
        var nodeArrowSelectTexture = null;

        var arrowObjMeshPy = -0.3;
        var arrowObjMeshRz = Math.PI;
        var curNodeArrowArr = null;
        var curNodeArrowCnt = 0;
        var arrowSelected = false;
        var arrowSelectedId;
        var arrowSelectedNodeId;
        var arrowIntersect;
        var arrowRayCaster = new THREE.Raycaster();

        var logoGeometry = null;
        var logoMaterial = null;
        var logoMesh = null;
        var logoTexture = null;
        var logoTextureUrl = $('#logo_url_input').val();

        var musicAudio = document.getElementById('music_audio');
        var musicUrl = $('#music_url_input').val();

        var sphereGeometryRadius = 30;
        var sphereGeometrySegment = 80;
        var sphereLon = 0;
        var sphereLat = -20;
        var sphereNearRadius = 4;
        var transitStep = 0.05;

        var isInteracting = false;

        var step = 0.6;
        var averLonSpeed = 0;
        var averLatSpeed = 0;
        var curLonSpeed = 0;
        var curLatSpeed = 0;
        var captureIntervalId = 1;
        var captureIntervalTime = 1000;
        var captureSphereLon = 0;
        var captureSphereLat = 0;
        var captureStartTime = 0;

        var mouse = new THREE.Vector2();
        var mouseMoveDiffLon = 0;
        var mouseMoveDiffLat = 0;

        var isLoading = false;

        var rotationAniOrigin = null;
        var rotationAniTarget = null;
        var rotationAniTween = null;
        var isRotating = false;


        var version = null;
        var resolution = null;
        var mapCanvasWidth = $('#map_canvas').width();
        var mapCanvasHeight = $('#map_canvas').height();
        var originX = 0.0;
        var originY = 0.0;
        var mapWidth = 0;
        var mapHeight = 0;
        var mapCenterX = mapCanvasWidth / 2;
        var mapCenterY = mapCanvasHeight / 2;
        var mapOriginX = 0;
        var mapOriginY = 0;
        var mapScale = 1.0;
        var mapUrl = $('#map_url_input').val();
        var mapLoaded = false;
        var mapRaster = null;
        var prjUrl = $('#prj_url_input').val();
        var prjLoaded = false;

        var dataObj = null;
        var pathObj = null;

        var nodeRadius = 6;
        var mapNodeNum = 0;
        var mapNodeArr = [];
        var curNodeId = 0;
        var curNodeCircle = null;
        var curNodeRadius = 8;
        var originNodeId = 0;
        const NODE_STATE_NORMAL = 0x0001;
        const NODE_STATE_FOCUSED = 0x0002;
        const NODE_STATE_SELECTED = 0x0004;
        const NODE_STATE_ORIGIN = 0x0003;

        var pathNum = 0;
        var pathArr = [];

        const PATH_STATE_NORMAL = 0x0001;
        const PATH_STATE_FOCUSED = 0x0002;


        loadData();

        function loadData() {

            getConf();

            var timerId = window.setInterval(function () {
                if(confLoaded) {
                    window.clearInterval(timerId);
                    render();
                }
            }, 10);
        }

        function getConf() {

            $.get(confUrl, function(result) {

                if(!result) return;

                try {
                    var data = JSON.parse(result);
                    nodeOriginId = data[0];
                    nodeArr = data[1];
                    nodeNum = nodeArr.length;
                    if(nodeNum < 0)  return;

                    confLoaded = true;
                } catch (e) {
                    alert('conf解析失败！' + e.name + ": " + e.message);
                }
            });
        }

        function render() {

            convert();
            setEnv();
            setMusic();
            setImgSize();
            setRes();
            setObj();
            setRSC();
            setTextureManager();
            setVisible();
            setNode(nodeOriginId);
            setListener();
            canvasAnimate();
            setMap();

            function convert() {
                for(var i = 0; i < nodeNum; i++) {
                    nodeArr[i].id = i;
                    nodeArr[i][1] = nodeArr[i][1] / 2;
                    var num = nodeArr[i][3].length;
                    if(num > 0) {
                        for(var j = 0; j < num; j++) {
                            nodeArr[i][3][j][0] = Math.floor(nodeArr[i][3][j][0]);
                            nodeArr[i][3][j][1] = nodeArr[i][3][j][1] / 3;
                        }
                    }
                }
            }

            function setEnv() {

                rotationAniOrigin = {lon:step, lat:step};
                rotationAniTarget = {lon:0, lat:0};
                rotationAniTween = new TWEEN.Tween(rotationAniOrigin).to(rotationAniTarget, 2000);
                rotationAniTween.onUpdate(rotationAnimate);
                rotationAniTween.easing(TWEEN.Easing.Quadratic.Out);
                rotationAniTween.onComplete(rotationAnimateStop);
            }

            function setMusic() {

                if(musicUrl) {
                    musicAudio.src = musicUrl;
                    musicAudio.loop = true;
                    $('#music_btn').click(function() {
                        if(musicAudio.paused){
                            musicAudio.play();
                            var rotation = function (){
                                $("#music_btn").rotate({
                                    angle:0,
                                    animateTo:360,
                                    callback: rotation,
                                    easing: function (x, t, b, c, d) {
                                        return c * (t / d) + b;
                                    }
                                });
                            };
                            rotation();
                            return;
                        }
                        musicAudio.pause();
                        $("#music_btn").stopRotate();
                    });
                }
            }

            function setImgSize() {

                var hdImgWidth = 4096;

                for(var i = 0; i < nodeNum; i++) {

                    nodeArr[i][0] += '?imageView2/0/w/' + hdImgWidth + '/h/' + hdImgWidth / 2 + '/format/jpg/interlace/1/q/75/ignore-error/1';

                }
            }

            function setRes() {

                setArrowTexture();
            }

            function setArrowTexture() {

                nodeArrowNormalTexture = textureLoader.load(nodeArrowNormalUrl);
                nodeArrowSelectTexture = textureLoader.load(nodeArrowSelectUrl);

                if(logoTextureUrl) {
                    logoTexture = textureLoader.load(logoTextureUrl);
                }
            }

            function setObj() {

                if(logoTextureUrl) {

                    logoGeometry = new THREE.CircleGeometry(3, 32, 0, 2 * Math.PI);
                    logoMaterial = new THREE.MeshBasicMaterial();
                    logoMaterial.map = logoTexture;
                    logoMaterial.side = THREE.DoubleSide;
                    logoMaterial.transparent = true;
                    logoMaterial.blending = THREE.CustomBlending;
                    logoMaterial.blendSrc = THREE.OneFactor;
                    logoMesh = new THREE.Mesh(logoGeometry, logoMaterial);

                    logoMesh.position.x = 0;
                    logoMesh.position.y = -29;
                    logoMesh.position.z = 0;

                    logoMesh.rotation.x = -Math.PI / 2;
                    logoMesh.rotation.y = 0;
                    logoMesh.rotation.z = 0;
                }
            }


            function setRSC() {

                renderer = new THREE.WebGLRenderer({canvas: canvas});
                renderer.setPixelRatio(window.devicePixelRatio);
                renderer.setClearColor(0x000000);
                renderer.setSize(canvasWidth, canvasHeight);
                renderer.sortObjects = false;

                effect = new THREE.StereoEffect(renderer);

                setCamera();
                scene = new THREE.Scene();
                scene.add(camera);

                var targetStarGeometry = new THREE.RingGeometry(0.05, 0.1, 32, 32, 0, Math.PI /6);
                var targetStarMaterial = new THREE.MeshBasicMaterial();
                targetStarMaterial.color.setHex(0xff0000);
                targetStarMaterial.side = THREE.DoubleSide;
                targetStarMaterial.alphaTest = 0.99;
                targetStarMaterial.depthTest = true;

                targetStar = new THREE.Mesh(targetStarGeometry, targetStarMaterial);
                targetStar.rotation.y = Math.PI / 2;
            }

            function setCamera() {

                camera = new THREE.PerspectiveCamera(cameraFov, elementAspect, cameraNearDis, cameraFarDis);
                camera.target = new THREE.Vector3(0, 0, 0);
                setCameraPosition();
            }

            function setCameraPosition() {

                cameraPx = cameraDis * Math.sin(cameraPhi) * Math.cos(cameraTheta);
                cameraPy = cameraDis * Math.cos(cameraPhi);
                cameraPz = cameraDis * Math.sin(cameraPhi) * Math.sin(cameraTheta);
                camera.position.set(cameraPx, cameraPy, cameraPz);
            }

            function setCameraRotation() {

                sphereLat = Math.max(-70, Math.min(60, sphereLat));
                cameraPhi = THREE.Math.degToRad(90 - sphereLat);
                cameraTheta = THREE.Math.degToRad(sphereLon);

                camera.target.x = 1000 * Math.sin(cameraPhi) * Math.cos(cameraTheta);
                camera.target.y = 1000 * Math.cos(cameraPhi);
                camera.target.z = 1000 * Math.sin(cameraPhi) * Math.sin(cameraTheta);

                camera.lookAt(camera.target);
            }

            function setTextureManager() {

                textureLoadManager.onProgress = function (textUrl, loaded, total) {

                    for(var i = 0; i < nodeNewLoadDataArr.length; i++) {
                        if(nodeNewLoadDataArr[i].sphereImageTextureUrl == md5(textUrl)) {
                            nodeNewLoadDataArr[i].sphereImageTextureLoaded = true;
                        }
                    }
                };
                textureLoadManager.onError = function () {

                };
                textureLoadManager.onLoad = function () {
                };
            }

            function setVisible() {

                window.setInterval(function () {
                    if(isLoading || isInteracting || isRotating) {
                        return;
                    }
                    if(nodeNewLoadDataArr) {
                        for(var i = 0; i < nodeNewLoadDataArr.length; i++) {

                            if(!nodeNewLoadDataArr[i].sphereMesh.visible) {
                                nodeNewLoadDataArr[i].sphereMesh.visible = true;
                            }
                        }
                    }
                }, 10);
            }

            function setNode(nodeId) {

                curNodeArrowArr = nodeArr[nodeId][3];
                curNodeArrowCnt = curNodeArrowArr.length;

                nodeOldLoadIdArr = null;
                nodeOldLoadIdArr = util.deepCopy(nodeNewLoadIdArr);

                nodeNewLoadIdArr = null;
                nodeNewLoadIdArr = [];
                nodeNewLoadIdArr.push(nodeId);
                for(var i = 0; i < curNodeArrowCnt; i++) {
                    nodeNewLoadIdArr.push(curNodeArrowArr[i][0]);
                }

                nodeOldLoadDataArr = null;
                nodeOldLoadDataArr = util.deepCopy(nodeNewLoadDataArr);

                nodeNewLoadDataArr = null;
                nodeNewLoadDataArr = [];

                for(var j = 0; j < nodeNewLoadIdArr.length; j++) {
                    var index = $.inArray(nodeNewLoadIdArr[j], nodeOldLoadIdArr);
                    if(index != -1) {
                        nodeNewLoadDataArr[j] = nodeOldLoadDataArr[index];
                    } else {
                        nodeNewLoadDataArr[j] = getNode(nodeNewLoadIdArr[j]);
                    }
                }

                curNodeObj = nodeNewLoadDataArr[0];
                curNodeSphereMesh = curNodeObj.sphereMesh;
                if(!curNodeSphereMesh.visible) {
                    curNodeSphereMesh.visible = true;
                }
                curNodeArrowCtnObj = curNodeObj.arrowCtnObj;

                if(!curNodeObj.sphereImageTextureLoaded) {
                    $('#spinner').show();
                    isLoading = true;
                    var count = 0;
                    var id = window.setInterval(function () {

                        if(count > 1500) {
                            window.clearInterval(id);
                            $('#spinner').hide();
                            $('#cover_img').hide();
                            isLoading = false;
                        }

                        if(curNodeObj.sphereImageTextureLoaded) {
                            window.clearInterval(id);
                            $('#spinner').hide();
                            $('#cover_img').hide();
                            isLoading = false;
                            setCurWidget();
                        }
                        count++;
                    }, 10);
                } else {
                    setCurWidget();
                }

                curNodeId = nodeId;
            }

            function setCurWidget() {

                releaseMemory();
                removeScene();

                if(curNodeSphereMesh) {
                    scene.add(curNodeSphereMesh);
                }

                if(logoMesh) {
                    logoMesh.visible = true;
                    scene.add(logoMesh);
                }

                if(targetStar) {
                    targetStar.visible = false;
                    scene.add(targetStar);
                }

                if(curNodeArrowCtnObj) {
                    curNodeArrowCtnObj.visible = true;
                    scene.add(curNodeArrowCtnObj);
                }

                setCameraRotation();
                setCurArrowCtnObjPosition();
                setCurArrowCtnObjRotation();
                setNearNode();

                if(musicUrl) {
                    $('#music_btn').show();
                }

                $('#vr_btn').show();
            }

            function releaseMemory() {

                if(!nodeOldLoadIdArr) {
                    return;
                }

                for(var i = 0; i < nodeOldLoadIdArr.length; i++) {

                    var index = $.inArray(nodeOldLoadIdArr[i], nodeNewLoadIdArr);
                    if(index == -1) {
                        var nodeObj = getOldLoadNodeObj(nodeOldLoadIdArr[i]);
                        nodeObj.sphereMesh.visible = false;
                        nodeObj.sphereMesh = null;
                        nodeObj.id = null;
                        nodeObj.agly = null;
                        nodeObj.sphereImageTextureUrl = null;
                        nodeObj.sphereImageTextureLoaded = null;
                        nodeObj.sphereMesh = null;
                        nodeObj.sphereGeometry.dispose();
                        nodeObj.sphereMaterial.dispose();
                        nodeObj.sphereTexture.dispose();
                        nodeObj.sphereGeometry = null;
                        nodeObj.sphereMaterial = null;
                        nodeObj.sphereTexture = null;

                        for(var j = 0; j < nodeObj.arrowCtnObj.children.length; j++) {
                            nodeObj.arrowCtnObj.children[j].children[0].geometry.dispose();
                            nodeObj.arrowCtnObj.children[j].children[0].material.dispose();
                            nodeObj.arrowCtnObj.children[j].children[0].geometry = null;
                            nodeObj.arrowCtnObj.children[j].children[0].material = null;
                            nodeObj.arrowCtnObj.children[j].visible = false;
                        }
                        nodeObj.arrowCtnObj = null;
                        nodeObj = null;
                        delete(nodeObj);
                    }
                }

                nodeOldLoadIdArr = null;
                nodeOldLoadDataArr = null;
            }

            function removeScene() {

                for(var i = 0; i < scene.children.length; i++) {
                    scene.remove(scene.children[i]);
                }
            }

            function setNearNode() {

                for(var i = 0; i < curNodeArrowCnt; i++) {

                    var sphereMesh = nodeNewLoadDataArr[i + 1].sphereMesh;
                    if(sphereMesh) {
                        var angle = curNodeArrowArr[i][1] - Math.PI / 2;
                        sphereMesh.position.x = sphereNearRadius * Math.cos(angle);
                        sphereMesh.position.z =  sphereNearRadius * Math.sin(angle);
                        sphereMesh.material.opacity = 0;
                        scene.add(sphereMesh);
                    }
                }
            }

            function getNode(nodeId) {

                var nodeObj = {};
                nodeObj.id = nodeId;
                nodeObj.agly = nodeArr[nodeId][1];
                nodeObj.sphereGeometry = new THREE.SphereGeometry(sphereGeometryRadius, sphereGeometrySegment, sphereGeometrySegment);
                nodeObj.sphereMaterial =  new THREE.MeshBasicMaterial();
                nodeObj.sphereMesh = new THREE.Mesh(nodeObj.sphereGeometry, nodeObj.sphereMaterial);
                nodeObj.sphereMesh.scale.x = -1;
                nodeObj.sphereMesh.visible = false;
                nodeObj.sphereMesh.rotation.y = nodeObj.agly;
                nodeObj.sphereMesh.material.transparent = true;
                nodeObj.sphereMesh.material.blending = THREE.AdditiveBlending;
                nodeObj.sphereMesh.material.depthWrite = false;
                nodeObj.sphereTexture = textureLoader.load(nodeArr[nodeId][0]);
                nodeObj.sphereMesh.material.map = nodeObj.sphereTexture;
                nodeObj.sphereImageTextureUrl = md5(nodeArr[nodeId][0]);
                nodeObj.sphereImageTextureLoaded = false;
                nodeObj.arrowCtnObj = new THREE.Object3D();

                var arrowConfigArr = nodeArr[nodeId][3];
                var curNodeArrowCnt = arrowConfigArr.length;
                for(var i = 0; i < curNodeArrowCnt; i++) {

                    var arrowGeometry = new THREE.PlaneGeometry(0.15, 0.1, 0.5, 0.5);

                    var arrowMaterial = new THREE.MeshBasicMaterial();
                    arrowMaterial.map = nodeArrowNormalTexture;
                    arrowMaterial.side = THREE.DoubleSide;
                    arrowMaterial.transparent = true;
                    arrowMaterial.blending = THREE.CustomBlending;
                    arrowMaterial.blendSrc = THREE.OneFactor;
                    arrowMaterial.shininess = 66;

                    var arrowMesh = new THREE.Mesh(arrowGeometry, arrowMaterial);
                    arrowMesh.position.y = arrowObjMeshPy;
                    arrowMesh.rotation.z = arrowObjMeshRz;
                    arrowMesh.renderOrder = 1;

                    var arrowObj = new THREE.Object3D();
                    arrowObj.agl = arrowConfigArr[i][1];
                    arrowObj.rotation.z = arrowObj.agl;
                    arrowObj.add(arrowMesh);

                    nodeObj.arrowCtnObj.add(arrowObj);
                }

                return nodeObj;
            }

            function setListener() {

                canvas.removeEventListener('touchstart', onTouchStart, false);
                canvas.removeEventListener('touchmove', onTouchMove, false);
                canvas.removeEventListener('touchend', onTouchEnd, false);

                if(isVR) {
                    window.removeEventListener('deviceorientation', setOrientationControls, true);
                    window.addEventListener('deviceorientation', setOrientationControls, true);
                } else {
                    canvas.addEventListener('touchstart', onTouchStart, false);
                    canvas.addEventListener('touchmove', onTouchMove, false);
                    canvas.addEventListener('touchend', onTouchEnd, false);
                }

                window.removeEventListener('resize', resize, true);
                window.addEventListener('resize', resize, false);

                $('#vr_btn').unbind('click', onVRClick);
                $('#vr_btn').bind('click',onVRClick);

                $('#map_btn').click(function() {
                    $('#map_close_btn').css({"display":"block"});
                    $('.map_container').css({"z-index":"2"});
                });

                $('#map_close_btn').click(function() {
                    $('#map_close_btn').css({"display":"none"});
                    $('.map_container').css({"z-index":"0"});
                });
            }

            function onTouchStart(event) {

                event.preventDefault();

                if(isLoading) {
                    return;
                }

                rotationAniTween.stop();
                isRotating = false;
                window.clearInterval(captureIntervalId);

                isInteracting = true;

                onPointerDownPointerX = event.changedTouches[0].pageX;
                onPointerDownPointerY = event.changedTouches[0].pageY;

                onPointerDownLon = sphereLon;
                onPointerDownLat = sphereLat;

                mouse.x = (event.changedTouches[0].pageX / canvasWidth) * 2 - 1;
                mouse.y = -(event.changedTouches[0].pageY / canvasHeight) * 2 + 1;

                captureStartTime = Date.now();
            }

            function onTouchMove(event) {

                if(isLoading) {
                    return;
                }

                if (isInteracting) {

                    sphereLon = (onPointerDownPointerX - event.changedTouches[0].pageX) * 0.1 + onPointerDownLon;
                    sphereLat = (event.changedTouches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;

                    setCameraRotation();
                    setCurArrowCtnObjPosition();
                    setCurArrowCtnObjRotation();

                    captureIntervalId = window.setTimeout(function () {

                        captureSphereLon = (onPointerDownPointerX - event.changedTouches[0].pageX) * 0.1 + onPointerDownLon;
                        captureSphereLat = (event.changedTouches[0].pageY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;

                    }, captureIntervalTime);

                }

                mouse.x = (event.changedTouches[0].pageX / canvasWidth) * 2 - 1;
                mouse.y = -(event.changedTouches[0].pageY / canvasHeight) * 2 + 1;
            }

            function onTouchEnd() {

                if(isLoading) {
                    return;
                }

                isInteracting = false;

                mouseMoveDiffLon = Math.abs(sphereLon - onPointerDownLon);
                mouseMoveDiffLat = Math.abs(sphereLat - onPointerDownLat);

                if(mouseMoveDiffLon < 0.2 && mouseMoveDiffLat < 0.1) {
                    if(arrowSelected) {

                        var nodeObj = getLoadNodeObj(arrowSelectedNodeId);
                        if(!nodeObj.sphereImageTextureLoaded) {

                            $('#spinner').show();
                            isLoading = true;
                            var count = 0;

                            var id = window.setInterval(function () {
                                if(count > 1000) {
                                    window.clearInterval(id);
                                    $('#spinner').hide();
                                    isLoading = false;
                                }

                                if(nodeObj.sphereImageTextureLoaded) {
                                    window.clearInterval(id);
                                    $('#spinner').hide();
                                    isLoading = false;
                                    transitAnimate();
                                }

                                count++;
                            }, 10);
                        } else {
                            transitAnimate();
                        }
                    }
                    return false;
                }

                if(mouseMoveDiffLon < 5 && mouseMoveDiffLat < 5) {
                    window.clearInterval(captureIntervalId);
                    return;
                }

                curLonSpeed = (Math.abs(captureSphereLon - sphereLon));
                curLatSpeed = (Math.abs(captureSphereLat - sphereLat));

                if(curLonSpeed < 5 && curLatSpeed < 5) {
                    window.clearInterval(captureIntervalId);
                    return;
                }

                var time = Date.now() - captureStartTime;
                averLonSpeed = mouseMoveDiffLon / time * 10;
                averLatSpeed = mouseMoveDiffLat / time * 10;

                if(averLonSpeed < 0.3 && averLatSpeed < 0.3) {
                    return;
                }

                rotationAniOrigin.lon = averLonSpeed;
                rotationAniOrigin.lat = averLatSpeed;

                rotationAniTween.stop();
                rotationAniTween.start();
                isRotating = true;
            }

            function setOrientationControls(e) {
                if (!e.alpha) {
                    return;
                }

                controls = new THREE.DeviceOrientationControls(camera, true);
                controls.connect();
                controls.update();

                window.removeEventListener('deviceorientation', setOrientationControls, true);
            }

            function resize() {

                canvasWidth = $(window).width();
                canvasHeight = $(window).height();

                orientationChange();
                updateScene();
            }

            function transitAnimate() {

                mouse.x = 0;
                mouse.y = 0;

                cameraDis = 0;
                setCameraPosition();
                setCurArrowCtnObjPosition();

                var transitAngle = curNodeArrowArr[arrowSelectedId][1] - Math.PI / 2;
                var transitDis = sphereNearRadius;
                var transitStepCnt = 0;
                var transitX = 0;
                var transitZ = 0;
                var transitOpacityStep = transitStep / sphereNearRadius;
                var transitOpacity = 0;

                if(curNodeArrowCtnObj) {
                    curNodeArrowCtnObj.visible = false;
                }

                if(logoMesh) {
                    logoMesh.visible = false;
                }

                if(!curNodeSphereMesh.visible) {
                    nextNodeSphereMesh.visible = true;
                }
                curNodeSphereMesh.material.transparent = true;
                curNodeSphereMesh.material.blending = THREE.AdditiveBlending;
                curNodeSphereMesh.material.depthWrite = false;

                nextNodeSphereMesh = getLoadNodeObj(arrowSelectedNodeId).sphereMesh;
                if(!nextNodeSphereMesh.visible) {
                    nextNodeSphereMesh.visible = true;
                }
                nextNodeSphereMesh.material.transparent = true;
                nextNodeSphereMesh.material.blending = THREE.AdditiveBlending;
                nextNodeSphereMesh.material.depthWrite = false;
                nextNodeSphereMesh.material.opacity = transitOpacity;

                var timerId = window.setInterval(function() {

                    if(transitStep * transitStepCnt >= transitDis) {
                        window.clearInterval(timerId);
                        curNodeSphereMesh.material.opacity = 0;
                        nextNodeSphereMesh.position.x = 0;
                        nextNodeSphereMesh.position.z = 0;
                        nextNodeSphereMesh.material.opacity = 1;
                        arrowSelected = false;

                        setNode(arrowSelectedNodeId);

                        return;
                    }

                    transitX = -transitStep * Math.cos(-transitAngle);
                    transitZ = transitStep * Math.sin(-transitAngle);

                    curNodeSphereMesh.position.x += transitX;
                    curNodeSphereMesh.position.z += transitZ;
                    nextNodeSphereMesh.position.x += transitX;
                    nextNodeSphereMesh.position.z += transitZ;

                    if(transitOpacity >= 1) {
                        transitOpacity = 1;
                    }
                    curNodeSphereMesh.material.opacity = 1 - transitOpacity;
                    nextNodeSphereMesh.material.opacity = transitOpacity;

                    transitOpacity += transitOpacityStep;
                    transitStepCnt++;
                }, 0.01);
            }

            function rotationAnimate() {

                if((sphereLon - onPointerDownLon) > 0) {
                    sphereLon = sphereLon + rotationAniOrigin.lon;
                } else {
                    sphereLon = sphereLon - rotationAniOrigin.lon;
                }

                if((sphereLat - onPointerDownLat) > 0) {
                    sphereLat = sphereLat + rotationAniOrigin.lat;
                } else {
                    sphereLat = sphereLat - rotationAniOrigin.lat;
                }

                setCameraRotation();
                setCurArrowCtnObjPosition();

                isRotating = true;
            }

            function rotationAnimateStop() {

                rotationAniTween.stop();
                window.clearInterval(captureIntervalId);
                isRotating = false;
            }

            function setCurArrowCtnObjPosition() {

                if(isVR) {

                    var vector = new THREE.Vector3();
                    camera.getWorldDirection(vector);

                    var x = vector.x;
                    var y = vector.y;
                    var z = vector.z;

                    cameraPhi = Math.atan(Math.sqrt(z * z + x * x) / y);
                    if(cameraPhi < 0) {
                        cameraPhi = Math.PI + cameraPhi;
                    }

                    if(z >= 0 && x >= 0) {
                        cameraTheta = Math.atan(z / x);
                    } else if(z > 0 && x < 0) {
                        cameraTheta = Math.atan(-x / z) + Math.PI / 2;
                    } else if(z < 0 && x < 0) {
                        cameraTheta = Math.atan(z / x) + Math.PI;
                    } else if(z < 0 && x > 0) {
                        cameraTheta = Math.atan(x / (-z)) + Math.PI * 1.5;
                    }

                    var dif = 0;
                    if(cameraPhi > 1.047197551196 && cameraPhi < 2.094395102393) {

                        for(var k = 0; k < curNodeArrowCnt; k++) {
                            if(cameraTheta > 4.712388980384 && cameraTheta < 6.283185307179) {
                                dif  = Math.abs(cameraTheta - 4.712388980384 - curNodeArrowCtnObj.children[k].agl);
                                if(dif < Math.PI / 18) {
                                    arrowSelectedId = k;
                                    break;
                                }
                            } else if(cameraTheta > 0 && cameraTheta < 4.712388980384) {
                                dif  = Math.abs(cameraTheta + 1.570796326794 - curNodeArrowCtnObj.children[k].agl);
                                if(dif < Math.PI / 18) {
                                    arrowSelectedId = k;
                                    break;
                                }
                            }
                        }

                        if(dif < Math.PI / 18) {
                            if(targetStarTrigCnt == 0) {
                                startTargetStarAnimation();
                            }
                            targetStarTrigCnt++;
                        } else {
                            stopTargetStarAnimation();
                        }
                    } else {
                        stopTargetStarAnimation();
                    }
                }

                if(curNodeArrowCtnObj) {
                    curNodeArrowCtnObj.position.x = (cameraDis + arrowCtnObjDis) * Math.sin(cameraPhi +
                            (Math.PI - Math.abs(cameraPhi - Math.PI * 0.6)) * 0.12) * Math.cos(cameraTheta);
                    curNodeArrowCtnObj.position.y = (cameraDis + arrowCtnObjDis) * Math.cos(cameraPhi +
                            (Math.PI - Math.abs(cameraPhi - Math.PI * 0.6)) * 0.12);
                    curNodeArrowCtnObj.position.z = (cameraDis + arrowCtnObjDis) * Math.sin(cameraPhi +
                            (Math.PI - Math.abs(cameraPhi - Math.PI * 0.6)) * 0.12) * Math.sin(cameraTheta);
                }

                if(targetStar) {
                    targetStar.position.x = curNodeArrowCtnObj.position.x;
                    targetStar.position.y = curNodeArrowCtnObj.position.y;
                    targetStar.position.z = curNodeArrowCtnObj.position.z;
                }
            }

            function startTargetStarAnimation() {

                if(nodeArrowSelectTexture) {
                    arrowSelectedNodeId = curNodeArrowArr[arrowSelectedId][0];
                    curNodeArrowCtnObj.children[arrowSelectedId].children[0].material.map = nodeArrowSelectTexture;
                    curNodeArrowCtnObj.children[arrowSelectedId].children[0].material.map.needsUpdate = true;
                }

                var thetaLength = 0;

                targetStarTid = window.setInterval(function () {
                    if(targetStarCnt >= 200) {
                        targetStar.visible = true;
                        if(targetStarCnt < 440) {
                            thetaLength += Math.PI / 120;
                            targetStar.geometry.dispose();
                            targetStar.geometry = new THREE.RingGeometry(0.03, 0.05, 32, 32, Math.PI / 2, thetaLength);
                            targetStar.geometry.dynamic = true;
                        } else {
                            stopTargetStarAnimation();
                            transitAnimate();
                        }
                    }
                    targetStarCnt++;
                }, targetStarTime);
            }

            function stopTargetStarAnimation() {

                targetStarCnt = 0;
                targetStarTrigCnt = 0;
                window.clearInterval(targetStarTid);
                targetStar.visible = false;

                for(var i = 0; i < curNodeArrowCnt; i++) {
                    if(nodeArrowNormalTexture) {
                        curNodeArrowCtnObj.children[i].children[0].material.map = nodeArrowNormalTexture;
                        curNodeArrowCtnObj.children[i].children[0].material.map.needsUpdate = true;
                    }
                }
            }

            function setCurArrowCtnObjRotation() {

                if(curNodeArrowCtnObj) {
                    curNodeArrowCtnObj.rotation.x = Math.PI / 2;
                    curNodeArrowCtnObj.rotation.y = 0;
                    curNodeArrowCtnObj.rotation.z = 0;
                }
            }

            function getLoadNodeObj(nid) {

                for(var i = 0; i < nodeNewLoadDataArr.length; i++) {
                    if(nodeNewLoadDataArr[i].id == nid) {
                        return nodeNewLoadDataArr[i];
                    }
                }
            }

            function getOldLoadNodeObj(nid) {

                for(var i = 0; i < nodeOldLoadDataArr.length; i++) {
                    if(nodeOldLoadDataArr[i].id == nid) {
                        return nodeOldLoadDataArr[i];
                    }
                }
            }

            function updateScene() {

                camera.aspect = canvasWidth / canvasHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(canvasWidth, canvasHeight);
                $('#msg_div').css({'height':canvasHeight + 'px', 'line-height':canvasHeight + 'px'});

                if(isVR) {
                    effect.setSize(canvasWidth, canvasHeight);
                }
                setListener();
                setCameraRotation();
                setCurArrowCtnObjPosition();
            }

            function canvasAnimate() {

                requestAnimationFrame(canvasAnimate);
                TWEEN.update();
                canvasRender();
            }

            function canvasRender() {

                if(isVR) {
                    update();
                    render();
                } else {

                    renderer.render(scene, camera);

                    if(!curNodeArrowCtnObj) {
                        return;
                    }

                    arrowRayCaster.setFromCamera(mouse, camera);

                    for(var i = 0; i < curNodeArrowCnt; i++) {
                        arrowIntersect = arrowRayCaster.intersectObject(curNodeArrowCtnObj.children[i].children[0]);
                        if(arrowIntersect.length > 0) {
                            arrowSelected = true;
                            arrowSelectedId = i;
                            arrowSelectedNodeId = curNodeArrowArr[i][0];
                            if(nodeArrowSelectTexture) {
                                curNodeArrowCtnObj.children[i].children[0].material.map = nodeArrowSelectTexture;
                            }
                            for(var k = 0; k < curNodeArrowCnt; k++) {
                                if(nodeArrowNormalTexture && k != i) {
                                    curNodeArrowCtnObj.children[k].children[0].material.map = nodeArrowNormalTexture;
                                }
                            }
                            break;
                        }
                        arrowSelected = false;
                    }
                    if(!arrowSelected) {
                        for(var j = 0; j < curNodeArrowCnt; j++) {
                            if(nodeArrowNormalTexture) {
                                curNodeArrowCtnObj.children[j].children[0].material.map = nodeArrowNormalTexture;
                            }
                        }
                    }
                    renderer.render(scene, camera);
                }
            }

            function update() {

                camera.updateProjectionMatrix();
                controls.update();

                setCurArrowCtnObjPosition();
            }

            function render() {

                effect.render(scene, camera);
            }

            function onVRClick() {
                if(isVR) {
                    isVR = false;
                    $(document).fullScreen(false);
                    stopTargetStarAnimation();
                    updateScene();
                } else {
                    $(document).fullScreen(true);
                    if(canvasWidth < canvasHeight) {
                        $('#msg_div').css({'height':canvasHeight + 'px', 'line-height':canvasHeight + 'px'});
                        $('#msg_div').text('turn phone landscape for VR').show();
                        $('#msg_close_btn').show();
                        $('#msg_close_btn').unbind('click');
                        $('#msg_close_btn').bind('click', function () {
                            $('#msg_div').text('turn phone landscape for VR').hide();
                            $('#msg_close_btn').hide();
                            isVR = false;
                            $(document).fullScreen(false);
                            stopTargetStarAnimation();
                            isVRReq = false;
                            updateScene();
                        });

                        isVRReq = true;
                    } else {
                        isVR = true;
                        updateScene();
                        $(document).fullScreen(true);
                    }
                }
            }

            function orientationChange() {

                if(canvasWidth > canvasHeight) {
                    if(isVRReq) {
                        $('#msg_div').text('turn phone landscape for VR').hide();
                        $('#msg_close_btn').hide();
                        isVR = true;
                        updateScene();
                        $(document).fullScreen(true);
                        isVRReq = false;
                    }
                } else {
                    if(isVR) {
                        $('#msg_div').text('turn phone landscape for VR').show();
                        $('#msg_close_btn').show();
                        $('#msg_close_btn').unbind('click');
                        $('#msg_close_btn').bind('click', function () {
                            $('#msg_div').text('turn phone landscape for VR').hide();
                            $('#msg_close_btn').hide();
                            isVR = false;
                            $(document).fullScreen(false);
                            stopTargetStarAnimation();
                            isVRReq = false;
                            updateScene();
                        });
                        isVR = false;
                        stopTargetStarAnimation();
                        isVRReq = true;
                    }
                }
            }
            function setMap() {

                paper.install(window);
                paper.setup('map_canvas');
                loadMap();
            }

            function loadMap() {

                getMap();
                getPrj();

                var timerId = window.setInterval(function () {
                    if(mapLoaded && prjLoaded) {
                        window.clearInterval(timerId);
                        mapRender();
                    }
                }, 10);
            }

            function getMap() {

                if(!mapUrl) {
                    alert('map url empty !');
                    return;
                }

                mapRaster = new Raster(mapUrl);
                mapRaster.position = view.center;
                mapRaster.on('load', function() {
                    mapLoaded = true;
                });
            }

            function getPrj() {

                if(!prjUrl) {
                    alert('prj url empty !');
                    return;
                }

                $.get(prjUrl, function(result) {
                    if(!result) return;

                    try {
                        dataObj = JSON.parse(result);
                    } catch (e) {
                        alert('data解析失败！' + e.name + ": " + e.message);
                        return;
                    }

                    version = dataObj[0] / 10;
                    resolution = dataObj[1] / 2;
                    mapWidth = dataObj[4] / 2;
                    mapHeight = dataObj[5] / 3;

                    originX = Math.abs(dataObj[2] / 3 / resolution);
                    originY = mapHeight - Math.abs(dataObj[3] / 4 / resolution);
                    originNodeId = dataObj[6][0];
                    pathObj = dataObj[6][1];

                    mapNodeNum = pathObj.length;
                    if(mapNodeNum < 0)  return;

                    prjLoaded = true;
                });
            }

            function mapRender() {

                mapConvertNodePath();
                mapSetNodeData();
                mapSetMapOrigin();
                mapTransNode();
                mapSetMapScale();
                mapScaleMap();
                mapDrawMap();
                mapScaleNode();
                mapListen();
                mapDrawNode();
                mapDrawPath();
                mapCanvasAnimate();
            }

            function mapConvertNodePath() {

                for(var i = 0; i < mapNodeNum; i++) {
                    pathObj[i].id = i;
                    pathObj[i][0] = pathObj[i][0] / 2 / resolution + originX;
                    pathObj[i][1] = -(pathObj[i][1] / 3) / resolution + originY;
                }
            }

            function mapSetNodeData() {

                for(var i = 0; i < mapNodeNum; i++) {
                    var point = {};
                    point.id = pathObj[i].id;
                    var x = pathObj[i][0];
                    var y = pathObj[i][1];
                    point.x = x;
                    point.y = y;
                    mapNodeArr.push(point);
                }
            }

            function mapSetMapOrigin() {

                mapOriginX = mapCanvasWidth / 2 - mapWidth / 2;
                mapOriginY = mapCanvasHeight / 2 - mapHeight / 2;
            }

            function mapTransNode() {

                for(var i = 0; i < mapNodeNum; i++) {
                    mapNodeArr[i].x = mapNodeArr[i].x + mapOriginX;
                    mapNodeArr[i].y = mapNodeArr[i].y + mapOriginY;
                }
            }

            function mapSetMapScale() {

                if(mapWidth >= mapHeight) {
                    mapScale = mapCanvasWidth / mapWidth;
                } else {
                    mapScale = mapCanvasHeight / mapHeight;
                }
            }

            function mapScaleMap() {

                mapWidth *= mapScale;
                mapHeight *= mapScale;

                mapSetMapOrigin();
            }

            function mapScaleNode() {

                for(var i = 0; i < mapNodeNum; i++) {

                    mapNodeArr[i].x = mapCenterX + (mapNodeArr[i].x - mapCenterX) * mapScale;
                    mapNodeArr[i].y = mapCenterY + (mapNodeArr[i].y - mapCenterY) * mapScale;
                }
            }

            function mapListen() {

                $('#map_canvas').mouseup(function(e) {

                    var movePoint = getMouseMovePoint(e.offsetX, e.offsetY);
                    if(movePoint != null) {
                        movePoint.state = NODE_STATE_FOCUSED;
                    }

                    updateMouseMovePoint(e.offsetX, e.offsetY);
                });

                $("#map_canvas").mousedown(function(e){

                    var downPoint = getMouseDownPoint(e.offsetX, e.offsetY);
                    if(downPoint != null) {
                        $('.map_container').css({"z-index":"0"});
                        setNode(downPoint.id);
                    }
                });
            }

            function getMouseMovePoint(mouseX, mouseY) {

                for(var i = 0; i < mapNodeNum; i++) {
                    var point = mapNodeArr[i];
                    if((point.x - nodeRadius) <= mouseX && mouseX <= (point.x + nodeRadius) &&
                        (point.y - nodeRadius) <= mouseY && mouseY <= (point.y + nodeRadius)) {
                        return mapNodeArr[i];
                    }
                }
                return null;
            }

            function updateMouseMovePoint(mouseX, mouseY) {

                for(var i = 0; i < mapNodeNum; i++) {
                    var point = mapNodeArr[i];
                    if((point.x - nodeRadius) > mouseX || mouseX > (point.x + nodeRadius) ||
                        (point.y - nodeRadius) > mouseY || mouseY > (point.y + nodeRadius)) {
                        if(point.state == NODE_STATE_FOCUSED) {
                            point.state = NODE_STATE_SELECTED;
                        }
                    }
                }
            }

            function getMouseDownPoint(mouseX, mouseY) {

                for(var i = 0; i < mapNodeNum; i++) {

                    var point = mapNodeArr[i];
                    if((point.x - nodeRadius) <= mouseX && mouseX <= (point.x + nodeRadius) &&
                        (point.y - nodeRadius) <= mouseY && mouseY <= (point.y + nodeRadius)) {

                        return point;
                    }
                }

                return null;
            }

            function mapDrawMap() {

                if(mapRaster) {
                    mapRaster.size = new Size(mapWidth, mapHeight);
                }
            }

            function mapDrawNode() {

                for(var i = 0; i < mapNodeNum; i++) {
                    mapNodeArr[i].state = NODE_STATE_NORMAL;
                    mapNodeArr[i].circle = new Path.Circle(new Point(mapNodeArr[i].x, mapNodeArr[i].y), nodeRadius);
                    mapNodeArr[i].circle.fillColor = 'black';
                }
            }

            function mapDrawNodeColor() {

                for(var i = 0; i < mapNodeNum; i++) {
                    if(mapNodeArr[i].circle != null) {
                        if(i == curNodeId) {
                            if(!curNodeCircle) {
                                curNodeCircle = new Path.Circle(new Point(mapNodeArr[i].x, mapNodeArr[i].y), curNodeRadius);
                            }
                            curNodeCircle.position = new Point(mapNodeArr[i].x, mapNodeArr[i].y);
                            curNodeCircle.fillColor = '#FF0000';
                        } else if(i == originNodeId) {
                            mapNodeArr[i].circle.fillColor = 'green';
                        } else {
                            switch(mapNodeArr[i].state) {
                                case NODE_STATE_ORIGIN:
                                    mapNodeArr[i].circle.fillColor = 'green';
                                    break;
                                case NODE_STATE_NORMAL:
                                    mapNodeArr[i].circle.fillColor = 'black';
                                    break;
                                case NODE_STATE_FOCUSED:
                                    mapNodeArr[i].circle.fillColor = '#FF0000';
                                    break;
                                case NODE_STATE_SELECTED:
                                    mapNodeArr[i].circle.fillColor = '#00BFFF';
                                    break;
                            }
                        }
                    }
                }
            }

            function mapDrawPath() {

                for(var i = 0; i < mapNodeNum; i++) {
                    var pathNum = pathObj[i][2].length;
                    if(pathNum > 0) {
                        var fromPoint = mapNodeArr[i];
                        for(var j = 0; j < pathNum; j++) {
                            pathObj[i][2][j] = Math.floor(pathObj[i][2][j]);
                            var toPoint = mapNodeArr[pathObj[i][2][j]];
                            var path = {};
                            path.fromPoint = fromPoint;
                            path.toPoint = toPoint;
                            var line = new Path.Line(path.fromPoint, path.toPoint);
                            line.strokeWidth = 2;
                            path.line = line;
                            path.state = PATH_STATE_NORMAL;
                            mapAddPath(path);
                        }
                    }
                }
            }

            function mapDrawPathColor() {

                pathNum = pathArr.length;
                for(var i = 0; i < pathNum; i++) {
                    if(pathArr[i].line != null) {
                        switch(pathArr[i].state) {
                            case PATH_STATE_NORMAL:
                                pathArr[i].line.strokeColor = '#00BFFF';
                                break;
                            case PATH_STATE_FOCUSED:
                                pathArr[i].line.strokeColor = 'green';
                                break;
                            case NODE_STATE_SELECTED:
                                pathArr[i].line.strokeColor = 'green';
                                break;
                        }
                    }
                }

            }

            function mapAddPath(path) {

                for(var i = 0; i < pathNum; i++) {
                    if((path.fromPoint.id == pathArr[i].fromPoint.id && path.toPoint.id == pathArr[i].toPoint.id) ||
                        (path.fromPoint.id == pathArr[i].toPoint.id && path.toPoint.id == pathArr[i].fromPoint.id)) {
                        return;
                    }
                }

                path.fromPoint.state = NODE_STATE_SELECTED;
                path.toPoint.state = NODE_STATE_SELECTED;

                path.state = PATH_STATE_NORMAL;

                pathArr.push(path);
                pathNum = pathArr.length;
            }

            function mapCanvasAnimate() {

                requestAnimationFrame(mapCanvasAnimate);
                mapCanvasRender();
            }

            function mapCanvasRender() {
                mapDrawNodeColor();
                mapDrawPathColor();
            }
        }
    }
});